﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using agsXMPP;

namespace PoshXmpp
{
    public class GroupChatManager : agsXMPP.protocol.x.muc.MucManager, IDisposable
    {
        public struct GroupChat
        {
            public Jid Room;
            public string Nick;
            public SortedList<Jid,string> Users;

            public GroupChat( Jid room, string nick )
            {
                Room = room;
                Nick = nick;
                Users = new SortedList<Jid, string>();
            }


            // override object.Equals
            public override bool Equals(object obj)
            {
                if (obj is Jid)
                {
                    return Equals((Jid)obj);
                }
                if (obj == null || GetType() != obj.GetType())
                {
                    return false;
                }
                return Room == ((GroupChat)obj).Room;
            }

            // override object.GetHashCode
            public override int GetHashCode()
            {
                return Room.GetHashCode();
            }
        }

        List<GroupChat> _rooms = new List<GroupChat>();
        XmppClient _client;

        public GroupChatManager(XmppClient connection)
            : base(connection)
        {
            _client = connection;
        }

        public void JoinRoom(Jid room)
        {
            JoinRoom(room, _client.Username, null);
        }

        new public void JoinRoom(Jid room, string nick)
        {
            JoinRoom(room, nick, null);
        }

        new public void JoinRoom(Jid room, string nick, string Password)
        {
            int r = _rooms.FindIndex(cr => cr.Room.Equals(room));

            if ( r >= 0)
            {
                GroupChat cr = _rooms[r];
                cr.Nick = nick;
                _rooms[r] = cr;
            }
            else
            {
                _rooms.Add(new GroupChat(room, nick));
            }
            base.JoinRoom(room, nick, Password);
            base.RequestList( agsXMPP.protocol.x.muc.Affiliation.member | 
                agsXMPP.protocol.x.muc.Affiliation.admin |
                agsXMPP.protocol.x.muc.Affiliation.outcast | 
                agsXMPP.protocol.x.muc.Affiliation.owner | agsXMPP.protocol.x.muc.Affiliation.none, room, null, null);

        }

        public void RefreshRooms()
        {
            foreach (GroupChat room in _rooms)
            {
                base.JoinRoom(room.Room, room.Nick);
            }
        }

        public void LeaveRoom(Jid room)
        {
            LeaveRoom(room, (from r in _rooms where r.Room.Equals(room) select r.Nick).FirstOrDefault());
        }

        new public void LeaveRoom(Jid room, string Nick)
        {
            _rooms.RemoveAll(cr => cr.Room == room);
            base.LeaveRoom(room, Nick);
        }

        public bool IsInRoom(Jid room)
        {
            return _rooms.Exists(cr => cr.Room.Equals(room));
        }

        public bool IsInRoom(string room)
        {
            return IsInRoom(new Jid(room));
        }

        /// <summary>
        /// Enumerable list of the rooms we're in.
        /// </summary>
        public List<GroupChat> Rooms
        {
            get
            {
                return _rooms;
            }
        }

        public GroupChat this[int index]
	    {
            get { return _rooms[index]; }
            set { _rooms[index] = value; }
	    }

        public GroupChat this[Jid room]
        {
            get { return _rooms.First(gc => gc.Room.Equals(room)); }
            set { _rooms[_rooms.FindIndex(gc => gc.Room.Equals(room))] = value; }
        }

        public SortedList<Jid,string> GetUsers(Jid room)
        {
            return this[room].Users;
        }

        public bool AddUser(Jid room, Jid user, string nick)
        {
            try
            {
                this[room].Users.Add(user,nick);
                return true;
            }
            catch { return false; }
        }

        public bool RemoveUser(Jid room, Jid user)
        {
            try
            {
                return this[room].Users.Remove(user);
            }
            catch { return false; }
        }

        #region IDisposable Members

        public void Close()
        {
            List<Jid> rooms = _rooms.ConvertAll<Jid>(cr => cr.Room);
            foreach (Jid room in rooms)
            {
                LeaveRoom(room);
            }
        }

        public void Dispose()
        {
            Close();
        }

        #endregion
    }
}
